
#include <BLine>
#include <BParticle>
#include "member_BParticle.h"

using namespace BWE;

#define member					(*(member_BParticle*)_ptr)
#define member_allocate()		_ptr = new member_BParticle(this)
#define member_release()		delete (member_BParticle*)_ptr

BParticle::BParticle()
{
	member_allocate();
}
BParticle::BParticle(const BParticle& other)
{
	member_allocate();
	this->copy(&other);
}
BParticle::~BParticle()
{
	member_release();
}

void BParticle::copy(const BShape* other)
{
	BShape::copy(other);
	if (const BParticle* particle = dynamic_cast<const BParticle*>(other))
	{
		member.size = particle_member(particle)->size;
		member.particleDuration = particle_member(particle)->particleDuration;
		member.emitterDuration = particle_member(particle)->emitterDuration;
		if (BByteArray* pixels = particle_member(particle)->pixels)
			member.pixels = new BByteArray(*pixels);
		member.dirty = particle_member(particle)->dirty;
	}
}
BShape* BParticle::clone() const
{
	return new BParticle(*this);
}

void BParticle::setPoints(BVector* points, int numPoints)
{
	member.points.clear();
	member.points.append(points, numPoints);
}
const BVector* BParticle::getPoints() const
{
	return member.points.data();
}
BVector* BParticle::getPoints()
{
	return member.points.data();
}

int BParticle::getNumPoints() const
{
	return member.points.size();
}
BVector BParticle::getPoint(int index) const
{
	return member.points[index];
}

void BParticle::addImage(BImage* image)
{

}
void BParticle::removeImage(BImage* image)
{

}
void BParticle::clearImages()
{

}

void BParticle::setParticleDuration(int seconds)
{
	if (member.particleDuration != seconds)
	{
		member.particleDuration = seconds;
	}
}
int BParticle::particleDuration() const
{
	return member.particleDuration;
}

void BParticle::setEmitterDuration(int seconds)
{
	if (member.emitterDuration != seconds)
	{
		member.emitterDuration = seconds;
	}
}
int BParticle::emitterDuration() const
{
	return member.emitterDuration;
}

void BParticle::setSize(const BRealSize& size)
{
	if (member.size != size)
	{
		member.size = size;
	}
}
const BRealSize& BParticle::size() const
{
	return member.size;
}

void BParticle::setAngularLimit(const BVector& minAngle, const BVector& maxAngle)
{

}

void BParticle::clear()
{

}

bool BParticle::query(const BString& text, BValue& value) const
{
	if (text == "vertices")
	{
		//value = member.vertices;
		return true;
	}
	return BShape::query(text, value);
}

BVector BParticle::inertia(BReal mass) const
{
	const BBox& box = this->box();
	BVector dimension = box.veca() + box.vecb() + box.vecc();

	BReal lx = 2 * dimension.x();
	BReal ly = 2 * dimension.y();
	BReal lz = 2 * dimension.z();

	BReal inex = mass / 12 * (ly * ly + lz * lz);
	BReal iney = mass / 12 * (lx * lx + lz * lz);
	BReal inez = mass / 12 * (lx * lx + ly * ly);

	return BVector(inex, iney, inez);
}
BVector BParticle::vertex(const BVector& direct) const
{
	struct SupportingCallback : public ITriangleCallback
	{
		const BVector& direct;
		BLine line;
		BReal maxRatio = 0;
		int count = 0;
		SupportingCallback(const BVector& dir, BReal length) : direct(dir)
		{
			line.setEnd(direct * length * 2);
		}
		virtual void process(const BTriangle& triangle, int triangleIndex)
		{
			count++;
			BReal ratio;
			if (line.intersect(triangle, ratio, true))
			{
				if (ratio > maxRatio)
				{
					maxRatio = ratio;
				}
			}
		}
	};
	SupportingCallback callback(direct, this->box().radius());
	member.overlapping(&callback, callback.line);
	return callback.line.vertex(callback.maxRatio);
}

void BParticle::refresh(BBox& box)
{
	box.reset(1, 1, 1);
}
void BParticle::render(BRender& render)
{

}
